package io.sundial.protocol.impl;

import io.sundial.conversion.Converter;
import io.sundial.conversion.exception.DeserializeException;
import io.sundial.conversion.exception.SerializeException;
import io.sundial.core.context.Context;
import io.sundial.core.lifecycle.Lifecycle;
import io.sundial.core.lifecycle.Stateful;
import io.sundial.core.lifecycle.exception.DestroyingException;
import io.sundial.core.lifecycle.exception.InitializingException;
import io.sundial.protocol.Protocol;

import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 基础协议
 *
 * @author Payne 646742615@qq.com
 * 2018/12/24 16:01
 */
public abstract class BasicProtocol extends Stateful implements Protocol {
    private Converter defaultConverter;
    private Map<String, Converter> supportConverters;

    @Override
    protected void initializing(Context context) throws InitializingException {
        super.initializing(context);

        // 如果没有设置就从上下文中找到所有的。
        if (supportConverters == null || supportConverters.isEmpty()) {
            Map<String, Converter> map = context.fetch(Converter.class);
            Collection<Converter> collection = map.values();
            Map<String, Converter> converters = new LinkedHashMap<>();
            for (Converter converter : collection) {
                String contentType = converter.getContentType();
                if (contentType == null || contentType.trim().isEmpty()) {
                    throw new InitializingException("converter " + converter.getClass() + " must declare a not null or blank Content-Type");
                }
                converters.put(contentType.trim().toUpperCase(), converter);
            }
            supportConverters = Collections.unmodifiableMap(converters);
        }

        // 如果没配置缺省转换器，就选择第一个作为默认的转换器。
        if (defaultConverter == null) {
            if (supportConverters.isEmpty()) {
                throw new InitializingException("please config at least one converter");
            } else {
                defaultConverter = supportConverters.values().iterator().next();
            }
        }

        for (Converter supportConverter : supportConverters.values()) {
            if (supportConverter instanceof Lifecycle) {
                ((Lifecycle) supportConverter).initialize(context);
            }
        }
        if (defaultConverter instanceof Lifecycle) {
            ((Lifecycle) defaultConverter).initialize(context);
        }
    }

    @Override
    protected void destroying() throws DestroyingException {
        super.destroying();

        for (Converter supportConverter : supportConverters.values()) {
            if (supportConverter instanceof Lifecycle) {
                ((Lifecycle) supportConverter).destroy();
            }
        }
        if (defaultConverter instanceof Lifecycle) {
            ((Lifecycle) defaultConverter).destroy();
        }

        supportConverters = null;

        defaultConverter = null;
    }

    protected String getContentType() {
        return defaultConverter.getContentType();
    }

    protected byte[] serialize(Object obj) throws SerializeException {
        return defaultConverter.serialize(obj);
    }

    protected <T> T deserialize(byte[] data, Class<T> type) throws DeserializeException {
        return defaultConverter.deserialize(data, type);
    }

    public Converter getDefaultConverter() {
        return defaultConverter;
    }

    public void setDefaultConverter(Converter defaultConverter) {
        this.defaultConverter = defaultConverter;
    }

    public Map<String, Converter> getSupportConverters() {
        return supportConverters;
    }

    public void setSupportConverters(Map<String, Converter> supportConverters) {
        this.supportConverters = supportConverters;
    }
}
